package com.qf.ticketredis.controller;

import com.qf.ticketredis.pojo.Ticket;
import com.qf.ticketredis.service.TicketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/ticket")
public class TicketController2 {

    @Autowired
    private TicketService ticketService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Value("${server.port}")
    private Integer port;


    private static final String LOCK_KEY_PREFIX = "LOCK:KEY:";
    private static final String LOCK_VALUE_PREFIX = "LOCK:VALUE:";

    @GetMapping("/sell/{id}")
    public void sell(@PathVariable("id") Integer id) throws InterruptedException {

        String key = LOCK_KEY_PREFIX + id;
        String value = LOCK_VALUE_PREFIX + port;

        //开启一个守护线程，给锁续时（看门狗程序-WatchDog）
        Thread watchDog = new Thread(()->{
            while (true) {
                //给当前进程加的锁续时（① 当前进程的锁 ② 锁快到期了重新续时为5s）
                String redisVal = redisTemplate.opsForValue().get(key);
                if (value.equals(redisVal)) {
                    //是我们自己加的锁
                    Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
                    if (ttl <= 2) { //快到期了
                        //续时
                        redisTemplate.expire(key, 3, TimeUnit.SECONDS);
                    }
                }
            }
        });
        //将这个线程设置为守护线程
        watchDog.setDaemon(true);
        watchDog.start();

        while (true){

            //利用setnx到redis实现加锁
            //设置加锁后，5秒超时释放，解决进程异常退出死锁问题
            Boolean lock = redisTemplate.opsForValue().setIfAbsent(key, value,3, TimeUnit.SECONDS);

            if (lock) {
                //获取锁成功
                try {
                    //查询id对应的票务信息，是否有剩余票
                    Ticket ticket = ticketService.getById(id);
                    Integer count = ticket.getCount();
                    if (count > 0) {
                        System.out.println("正在卖出第" + count + "张票");
                        //模拟卖票时间
                        Thread.sleep(4000);

                        count = count - 1;

                        //重新更新数据库的票务信息
                        ticket.setCount(count);
                        ticketService.updateById(ticket);
                        System.out.println("剩余票数为：" + count);
                    } else {
                        break;
                    }
                }finally {
                    //释放锁
                    redisTemplate.delete(key);
                }
            }

        }
    }
}
